<?php

namespace app\model;

use Laf\Log;
use mon\orm\Model;
use mon\util\Instance;
use mon\util\Container;
use mon\orm\exception\DbException;

/**
 * 管理员模型
 *
 * Class Admin
 * @copyright 2021-03-24 mon-console
 * @version 1.0.0
 */
class AdminModel extends Model
{
    use Instance;

    /**
     * 操作表
     *
     * @var string
     */
    protected $table = 'admin';

    /**
     * 新增自动写入字段
     *
     * @var array
     */
    protected $insert = ['create_time', 'update_time'];

    /**
     * 更新自动写入字段
     *
     * @var array
     */
    protected $update = ['update_time'];

    /**
     * 验证器
     *
     * @var string
     */
    protected $validate = \app\validate\Auth::class;

    /**
     * 查询信息
     *
     * @param array $where where条件
     * @param mixed $field 查询字段
     * @return mixed
     */
    public function getInfo(array $where, $field = '*')
    {
        $info = $this->where($where)->field($field)->find();
        if (!$info) {
            $this->error = '记录信息不存在';
            return false;
        }

        return $info;
    }

    /**
     * 用户登陆
     *
     * @param array $option 请求参数
     * @return mixed
     */
    public function login($option)
    {
        // 验证数据格式
        $check = $this->validate()->data($option)->scope('login')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }

        // 获取用户信息
        $userInfo = $this->getInfo(['username' => $option['username']]);
        if (!$userInfo) {
            $this->error = '用户不存在';
            return false;
        }
        if ($userInfo['status'] != '1') {
            $this->error = '用户已冻结';
            return false;
        }

        // 验证密码
        if ($userInfo['password'] != $this->encodePassword($option['password'], $userInfo['salt'])) {
            $this->error = '用户密码错误';
            return false;
        }

        // 验证用户过期时间
        if ($userInfo['deadline'] != 0 && $userInfo['deadline'] < time()) {
            $this->error = '用户已过期';
            return false;
        }

        // 定义登陆token
        $ip = Container::instance()->request->ip();
        $login_token = md5(randString() . $ip . time() . $userInfo['username']);

        $this->startTrans();
        try {
            Log::instance()->oss(__FILE__, __LINE__, 'update user login info', 'sql');
            $saveLogin = $this->save([
                'login_time'    => time(),
                'login_ip'      => $ip,
                'login_token'   => $login_token
            ], ['id' => $userInfo['id']]);
            if (!$saveLogin) {
                $this->rollBack();
                $this->error = '登陆失败';
                return false;
            }

            $userInfo['login_time'] = time();
            $userInfo['login_ip'] = $ip;
            $userInfo['login_token'] = $login_token;

            // 记录操作日志
            $record = AdminLogModel::instance()->record(['uid' => $userInfo['id'], 'action' => '管理员登录', 'content' => '管理员登录']);
            if (!$record) {
                $this->rollback();
                $this->error = '记录登录日志失败';
                return false;
            }

            $this->commit();
            return $userInfo;
        } catch (DbException $e) {
            $this->rollback();
            $this->error = '管理员登录异常';
            Log::instance()->oss(__FILE__, __LINE__, 'admin login exception, msg => ' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 新增用户
     *
     * @param array $option 请求参数
     * @return boolean|integer
     */
    public function add(array $option)
    {
        $check = $this->validate()->data($option)->scope('add_user')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }

        // 判断用户名是否已存在
        $userInfo = $this->where(['username' => $option['username']])->find();
        if ($userInfo) {
            $this->error = '用户名已存在';
            return false;
        }

        // 生成密码
        $salt = randString(6, 0);
        $password = $this->encodePassword($option['password'], $salt);

        $this->startTrans();
        try {
            $deadline = ($option['deadline']) ? strtotime($option['deadline'] . ' 23:59:59') : 0;
            $save = $this->save([
                'username'  => $option['username'],
                'salt'      => $salt,
                'password'  => $password,
                'status'    => 1,
                'avatar'    => '/static/img/avatar.png',
                'deadline'  => $deadline
            ], null, 'id');
            Log::instance()->oss(__FILE__, __LINE__, 'add admin', 'sql');
            if (!$save) {
                $this->rollback();
                $this->error = '新增用户失败';
                return false;
            }

            // 记录操作日志
            $record = AdminLogModel::instance()->record(['action' => '新增管理员', 'content' => '新增管理员：' . $option['username'] . ', 管理员ID：' . $save]);
            if (!$record) {
                $this->rollback();
                $this->error = '记录操作日志失败';
                return false;
            }

            $this->commit();
            return $save;
        } catch (DbException $e) {
            $this->rollback();
            $this->error = '新增管理员异常';
            Log::instance()->oss(__FILE__, __LINE__, 'add admin exception, msg => ' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 修改用户信息
     *
     * @param array $data
     * @return boolean
     */
    public function edit($data, $adminID)
    {
        $check = $this->validate()->data($data)->scope('edit_user')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }
        // 获取用户信息
        $info = $this->getInfo(['id' => $data['idx']]);
        if (!$info) {
            $this->error = '获取用户信息失败';
            return false;
        }
        $this->startTrans();
        try {
            $data['deadline'] = ($data['deadline']) ? strtotime($data['deadline'] . ' 23:59:59') : 0;
            $save = $this->allowField(['deadline'])->save($data, ['id' => $data['idx']]);
            if (!$save) {
                $this->rollBack();
                $this->error = '编辑管理员信息失败';
                return false;
            }

            // 记录操作日志
            $record = AdminLogModel::instance()->record(['action' => '编辑管理员', 'content' => '编辑管理员：' . $info['username'] . ', 操作管理员ID：' . $adminID]);
            if (!$record) {
                $this->rollback();
                $this->error = '记录操作日志失败';
                return false;
            }
            $this->commit();
            return true;
        } catch (DbException $e) {
            $this->rollback();
            $this->error = '编辑管理员异常';
            Log::instance()->oss(__FILE__, __LINE__, 'edit admin exception, msg => ' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 修改用户密码
     *
     * @param array $option 请求参数
     * @param boolean $checkOld 是否验证旧密码
     * @return boolean
     */
    public function reset_password(array $option, $checkOld = false)
    {
        $check = $this->validate()->data($option)->scope('reset_password')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }

        // 获取用户信息
        $info = $this->getInfo(['id' => $option['idx']]);
        if (!$info) {
            $this->error = '获取用户信息失败';
            return false;
        }
        // 判断是否需要验证旧密码，需验证旧密码时，需要多传oldpwd参数
        if ($checkOld) {
            $old_pwd = isset($option['oldpwd']) ? $option['oldpwd'] : '';
            $checkOldPwd = $this->validate()->data(['password' => $old_pwd])->scope(['password'])->check();
            if ($checkOldPwd !== true) {
                $this->error = $this->validate()->getError();
                return false;
            }
            if ($info['password'] != $this->encodePassword($old_pwd, $info['salt'])) {
                $this->error = '旧密码错误';
                return false;
            }
        }

        // 重新生成密码
        $salt = randString(6, 0);
        $password = $this->encodePassword($option['password'], $salt);

        $this->startTrans();
        try {
            Log::instance()->oss(__FILE__, __LINE__, 'modify admin password', 'sql');
            $save = $this->save([
                'salt'              => $salt,
                'password'          => $password,
            ], ['id' => $option['idx']]);
            if (!$save) {
                $this->rollback();
                $this->error = '修改用户密码失败';
                return false;
            }

            // 记录操作日志
            $record = AdminLogModel::instance()->record(['action' => '修改管理员密码', 'content' => '修改管理员密码, 管理员ID：' . $option['idx']]);
            if (!$record) {
                $this->rollback();
                $this->error = '记录操作日志失败';
                return false;
            }

            $this->commit();
            return true;
        } catch (DbException $e) {
            $this->rollback();
            $this->error = '修改管理员密码异常';
            Log::instance()->oss(__FILE__, __LINE__, 'modify admin password exception, msg => ' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 修改用户状态
     *
     * @param array $option
     * @return boolean
     */
    public function reset_status(array $option)
    {
        $check = $this->validate()->data($option)->scope('reset_status')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }

        // 获取用户信息
        $info = $this->getInfo(['id' => $option['idx']]);
        if (!$info) {
            $this->error = '获取用户信息失败';
            return false;
        }

        if ($option['status'] == $info['status']) {
            $this->error = '修改的状态与原状态一致';
            return false;
        }

        $this->startTrans();
        try {
            Log::instance()->oss(__FILE__, __LINE__, 'modify admin status', 'sql');
            $save = $this->save(['status' => $option['status']], ['id' => $option['idx']]);
            if (!$save) {
                $this->rollback();
                $this->error = '修改用户状态失败';
                return false;
            }

            // 记录操作日志
            $record = AdminLogModel::instance()->record(['action' => '修改管理员状态', 'content' => '修改管理员状态为：' . $option['status'] . ', 管理员ID：' . $option['idx']]);
            if (!$record) {
                $this->rollback();
                $this->error = '记录操作日志失败';
                return false;
            }

            $this->commit();
            return true;
        } catch (DbException $e) {
            $this->rollback();
            $this->error = '修改管理员状态异常';
            Log::instance()->oss(__FILE__, __LINE__, 'modify admin status exception, msg => ' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 查询用户列表
     *
     * @param array $option 请求参数
     * @param boolean $forGroup 是否为组别查询
     * @return array
     */
    public function queryList(array $option, $forGroup = false)
    {
        $limit = isset($option['limit']) ? intval($option['limit']) : 10;
        $page = isset($option['page']) && is_numeric($option['page']) ? intval($option['page']) : 1;

        // 查询
        if ($forGroup) {
            $list = $this->scope('listOfGroup', $option)->page($page, $limit)->select();
            $total = $this->scope('listOfGroup', $option)->count();
        } else {
            $list = $this->scope('list', $option)->page($page, $limit)->select();
            $total = $this->scope('list', $option)->count();
        }

        return [
            'list'      => $list,
            'total'     => $total,
            'pageSize'  => $limit,
            'page'      => $page
        ];
    }

    /**
     * 查询用户列表场景
     *
     * @param [type] $query
     * @param [type] $args
     * @return $this
     */
    protected function scopeList($query, $args)
    {
        $query->field(['id', 'username', 'avatar', 'status', 'login_ip', 'login_time', 'create_time', 'update_time', 'deadline']);
        // ID搜索
        if (isset($args['idx']) && $args['idx'] != '' && is_numeric($args['idx']) && is_int($args['idx'] + 0)) {
            $query->where('id', intval($args['idx']));
        }
        // status搜索
        if (isset($args['status']) && $args['status'] != '' && is_numeric($args['status']) && is_int($args['status'] + 0)) {
            $query->where('status', intval($args['status']));
        }
        // 按用户名
        if (isset($args['username']) && is_string($args['username']) && !empty($args['username'])) {
            $query->whereLike('username', trim($args['username']) . '%');
        }
        // 创建时间搜索
        if (isset($args['start_time']) && $args['start_time'] != '' && is_numeric($args['start_time']) && is_int($args['start_time'] + 0)) {
            $query->where('create_time', '>=', intval($args['start_time']));
        }
        if (isset($args['end_time']) && $args['end_time'] != '' && is_numeric($args['end_time']) && is_int($args['end_time'] + 0)) {
            $query->where('create_time', '<=', intval($args['end_time']));
        }
        // 登录时间搜索
        if (isset($args['login_start_time']) && is_numeric($args['login_start_time']) && is_int($args['login_start_time'] + 0) && $args['login_start_time'] != '') {
            $query->where('login_time', '>=', intval($args['login_start_time']));
        }
        if (isset($args['login_end_time']) && is_numeric($args['login_end_time']) && is_int($args['login_end_time'] + 0) && $args['login_end_time'] != '') {
            $query->where('login_time', '<=', intval($args['login_end_time']));
        }
        // 排序
        if (isset($args['order']) && isset($args['sort']) && in_array($args['order'], ['login_time', 'create_time', 'update_time', 'deadline']) && in_array($args['sort'], ['asc', 'desc'])) {
            $query->order($args['order'], $args['sort']);
        }

        return $query;
    }

    /**
     * 查询组别用户相关列表场景
     *
     * @param [type] $query 查询实例
     * @param [type] $args  查询参数
     * @return $this
     */
    protected function scopeListOfGroup($query, $args)
    {
        // 查询
        $field = ['a.id', 'a.username', 'a.avatar', 'a.status', 'a.login_ip', 'a.login_time', 'a.create_time', 'a.update_time', 'b.group_id', 'c.title as group_title'];
        $query->alias('a')->join(AuthAccessModel::instance()->getTable() . ' b', 'a.id=b.uid', 'left')->join(AuthGroupModel::instance()->getTable() . ' c', 'b.group_id=c.id', 'left')->field($field);
        // 存在组别
        if (isset($args['gid']) && is_numeric($args['gid']) && is_int($args['gid'] + 0) && $args['gid'] != '') {
            $query->where('b.group_id', $args['gid']);
        }
        // 存在指定非组别
        if (isset($args['not_gid']) && is_numeric($args['not_gid']) && is_int($args['not_gid'] + 0) && $args['not_gid'] != '') {
            $query->where('b.group_id', '<>', $args['not_gid']);
        }
        // ID搜索
        if (isset($args['idx']) && $args['idx'] != '' && is_numeric($args['idx']) && is_int($args['idx'] + 0)) {
            $query->where('a.id', intval($args['idx']));
        }
        // status搜索
        if (isset($args['status']) && $args['status'] != '' && is_numeric($args['status']) && is_int($args['status'] + 0)) {
            $query->where('a.status', intval($args['status']));
        }
        // 按用户名
        if (isset($args['username']) && is_string($args['username']) && !empty($args['username'])) {
            $query->whereLike('a.username', trim($args['username']) . '%');
        }
        // 创建时间搜索
        if (isset($args['start_time']) && $args['start_time'] != '' && is_numeric($args['start_time']) && is_int($args['start_time'] + 0)) {
            $query->where('a.create_time', '>=', intval($args['start_time']));
        }
        if (isset($args['end_time']) && $args['end_time'] != '' && is_numeric($args['end_time']) && is_int($args['end_time'] + 0)) {
            $query->where('a.create_time', '<=', intval($args['end_time']));
        }
        // 登录时间搜索
        if (isset($args['login_start_time']) && is_numeric($args['login_start_time']) && is_int($args['login_start_time'] + 0) && $args['login_start_time'] != '') {
            $query->where('a.login_time', '>=', intval($args['login_start_time']));
        }
        if (isset($args['login_end_time']) && is_numeric($args['login_start_time']) && is_int($args['login_end_time'] + 0) && $args['login_end_time'] != '') {
            $query->where('a.login_time', '<=', intval($args['login_end_time']));
        }
        // 排序
        if (isset($args['order']) && isset($args['sort']) && in_array($args['order'], ['login_time', 'create_time', 'update_time']) && in_array($args['sort'], ['asc', 'desc'])) {
            $query->order('a.' . $args['order'], $args['sort']);
        }

        return $query;
    }

    /**
     * 混淆加密密码
     *
     * @param string $password  密码
     * @param string $salt      加密盐
     * @return string
     */
    public function encodePassword($password, $salt)
    {
        return md5($password . $salt);
    }

    /**
     * 自动完成create_time字段
     * 
     * @param mixed $val 默认值
     * @param array  $row 列值
     * @return integer
     */
    protected function setCreateTimeAttr($val)
    {
        return time();
    }

    /**
     * 自动完成update_time字段
     * 
     * @param mixed $val 默认值
     * @param array  $row 列值
     * @return integer
     */
    protected function setUpdateTimeAttr($val)
    {
        return time();
    }
}
